# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: inkyu

import datetime

from coin.base.datetime_util import to_datetime
from coin.exchange.okex.kr_rest.product import OkexProduct
from coin.exchange.upbit_v1.kr_rest.product import UpbitProduct
from coin.strategy.mm.simple_sim import result_util
from coin.strategy.mm.simple_sim.strategy.kimchi import KimchiSimStrategy


def get_products(from_ts):
  return [
      OkexProduct.FromStr('BTC-USDT'),
      UpbitProduct.FromStr('BTC-KRW'),
      OkexProduct.FromStr('ETH-USDT'),
      UpbitProduct.FromStr('ETH-KRW'),
      OkexProduct.FromStr('EOS-USDT'),
      UpbitProduct.FromStr('EOS-KRW'),
      OkexProduct.FromStr('ETC-USDT'),
      UpbitProduct.FromStr('ETC-KRW'),
      OkexProduct.FromStr('BCH-USDT'),
      UpbitProduct.FromStr('BCH-KRW'),
  ]


def get_machines():
  return ['feed-01.ap-northeast-2.aws']


def get_time_ranges():
  ranges = []
  cur_dt = datetime.datetime(2018, 8, 16, 0, 0, 0)
  end_dt = datetime.datetime(2018, 8, 22, 0, 0, 0)
  while cur_dt < end_dt:
    ranges.append((cur_dt, cur_dt + datetime.timedelta(hours=24)))
    cur_dt += datetime.timedelta(hours=24)
  return ranges


def linear_sell_edge(edge, close_edge, max_pos, pos):
  if pos <= 0.:
    return edge
  elif pos >= max_pos:
    return close_edge
  else:
    p = (pos / float(max_pos))
    return (p * close_edge + (1 - p) * edge)


def linear_buy_edge(edge, close_edge, max_pos, pos):
  if pos >= 0.:
    return edge
  elif pos <= -max_pos:
    return close_edge
  else:
    p = (-pos / float(max_pos))
    return (p * close_edge + (1 - p) * edge)


def get_strategy(from_ts, to_ts):
  products = get_products(from_ts)
  product_pairs = list(zip(products[0::2], products[1::2]))

  NS_PER_SECOND = (10**9)
  NS_PER_MINUTE = 60 * NS_PER_SECOND

  strategy_list = []

  for basis_ma_window in [0]:
    for edge_bp in [0]:
      for close_edge_bp in [edge_bp]:
        stack = 5
        lot_size = 0.1
        pricing_param = {
            'basis_ma_window': basis_ma_window * NS_PER_MINUTE,
        }

        executor_param = {
            'passive_param': {  # Bitfinex
                'lot_size': lot_size,
                'min_pos': -lot_size * stack,
                'max_pos': lot_size * stack,
                'maker_fee': 0. / 10000.,
                'taker_fee': 10. / 10000.,
                'post_only': True,
                'trade_qty_func': lambda trade: trade.qty
            },
            'aggression_param': {  # Okex
                'max_qty': lot_size * 3,
                'maker_fee': 2. / 10000.,
                'taker_fee': 4. / 10000.,
                'trade_qty_func': lambda trade: trade.qty
            },
            'net_pos_allowance': lot_size * 2,  # TODO(inkyu): Fill me
        }

        name = '%02dm.%02dbp.%02dbp.%02dstack.%s' % (
            basis_ma_window, edge_bp, close_edge_bp, stack, to_datetime(from_ts).strftime('%Y%m%d'))

        strategy = KimchiSimStrategy(product_pairs,
                                     pricing_param,
                                     executor_param,
                                     name=name,
                                     feature_filepath=('upbit/feature.%s.csv' % name),
                                     fill_filepath=('upbit/fill.%s.csv' % name))
        strategy_list.append(strategy)

  return strategy_list


def get_strategy_result(strategy):
  return {'name': strategy.name, **strategy.get_summary()}


def aggregate_result(results):
  return result_util.aggregate_sim_result(results)
